package com.liz.lizrpccore.templates.excute;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author liangGongWei
 * @description
 * @create 2021-08-25 21:06
 **/

@Slf4j
@Component
public class ExecutorServiceComponent {
    private static final int INIT_THREADS = Runtime.getRuntime().availableProcessors() * 2;
    private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors() * 2;
    private static final int MAX_QUEUE_SIZE = 10000;
    private static final String POLL_NAME = "ExecutorServiceComponent-Pool";
    private static ExecutorService defaultExecutorService = new MonitoredThreadPoolExecutor(
            INIT_THREADS,
            MAX_THREADS,
            3600L,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(MAX_QUEUE_SIZE, true),
            new MyThreadFactory(POLL_NAME),
            new ThreadPoolExecutor.CallerRunsPolicy());
    private Map<String, ExecutorService> executorServiceRegister = new HashMap<String, ExecutorService>();
    private AtomicInteger poolCounter = new AtomicInteger(1);

    public static class MyThreadFactory implements ThreadFactory {
        private final AtomicLong counter = new AtomicLong(1);
        private String poolName;

        public MyThreadFactory(String poolName) {
            this.poolName = poolName;
        }

        public String getPoolName() {
            return this.poolName;
        }

        @Override
        public Thread newThread(Runnable r) {
            counter.getAndIncrement();
            Thread newThread = new Thread(r, this.poolName + "-" + r.getClass().getSimpleName() + "-" + counter.get());
            return newThread;
        }

    }

    public static ExecutorService getDefaultExecutorService() {
        return defaultExecutorService;
    }

    public ExecutorService newExecutorService(int maxThread) {
        String poolName = POLL_NAME + "-" + poolCounter.getAndIncrement();
        ExecutorService executorService = new MonitoredThreadPoolExecutor(INIT_THREADS, maxThread, 30L,
                TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(MAX_QUEUE_SIZE, true), new MyThreadFactory(poolName),
                new ThreadPoolExecutor.CallerRunsPolicy());
        this.executorServiceRegister.put(poolName, executorService);
        return executorService;
    }

    @PreDestroy
    public void destroy() throws Exception {
        log.info("spirng容器关闭时，关闭通用线程池:{}", POLL_NAME);
        defaultExecutorService.shutdown();
        for (Map.Entry<String, ExecutorService> e : this.executorServiceRegister.entrySet()) {
            log.info("spirng容器关闭时，关闭线程池:{}", e.getKey());
            e.getValue().shutdown();
        }

    }
}
